#ifndef __YHM_TYPES_H__
#define __YHM_TYPES_H__

#include <infiniband/verbs.h>
#include <unistd.h>
#include <stdlib.h>
#include "tools.h"
#include <deque>
#include <unordered_map>

#define SHORT_STR_LEN 32

struct input_param{
  //basic info
  char mc_ip[SHORT_STR_LEN];
  int mc_port;
  int master; //1 means master  
  int ib_port; //which ib port to use

  //info of which should boardcast
  int server_num;
  int client_num;
  long pool_size;
  char pool_name[SHORT_STR_LEN];
};
//qp's info for connecting a QP
struct qp_info{
  int lid;
  int qpn;
};  
struct mr_info{
  unsigned long addr;
  unsigned long size;
  unsigned int rkey;
};


#define SUPER_MAGIC 0x19990424LL
#define REGION_SHIFT 12
#define REGION_SIZE (1<<REGION_SHIFT) //1MB
#define BLOCK_SIZE REGION_SIZE
#define CHILD_NUM 8
#define MAX_MEMPOOL_NUM 1000
//block 's metadata
enum BLOCK_TYPE{
  BLOCK_TYPE_FREE = 0,
  BLOCK_TYPE_REGION, //region data block
  BLOCK_TYPE_NODE, //block for node data store
  BLOCK_TYPE_SUPER, //super block
  BLOCK_TYPE_META, //block for mempool metadata
  BLOCK_TYPE_RESERVE //block for reserve
};
struct block_data{
  unsigned long type;
};
struct node_pos{
  unsigned long bn : 32; // num for block (low)
  unsigned long nn : 32; // node in block (high)
};
struct node_data{
  struct node_pos ch[CHILD_NUM];
};
struct root_data{
  union{
    char __m[sizeof(struct node_data)];
    struct {
      unsigned long version;
      struct root_data *prev;
      struct root_data *next;
      struct node_pos root;
    };
  };
};
struct mempool_meta{
  unsigned long id : 16;
  unsigned long size : 48;
  struct node_pos root;
};
struct pm_super{
  unsigned long magic; //magic number
  unsigned long hash; //consistent hash
  struct mempool_meta mempool[MAX_MEMPOOL_NUM];
};
//the struct to build a pm
struct local_pm{
  int fd;
  void *addr;
  long size;
};

//for alloc block, node
struct pm_allocator{
  std::deque<int> free_block;
  std::deque<struct node_pos> free_node;
};



struct server_ctx{
  //input parameters
  struct input_param *param;
  //context of memcached
  struct mc_ctx *mi;
  //rdma main ctx
  struct ibv_context *ctx;
  //port attr
  struct ibv_port_attr port_attr;
  //protection domain
  struct ibv_pd *pd;
  //server id
  int id;

  //local memory info
  struct local_pm pm;
  struct pm_super *super;
  struct pm_allocator *allocator;

  //server QP
  struct ibv_qp **server_qp;
  struct ibv_cq **server_send_cq;
  struct ibv_cq *server_recv_cq; //shared recv cq

  //client QP
  struct ibv_qp **client_qp;
  struct ibv_cq **client_send_cq;
  struct ibv_cq *client_recv_cq; //shared recv cq

  //QP info
  struct qp_info *server_qp_info;
  struct qp_info *client_qp_info;

  //mr info
  struct mr_info *server_mr_info;
  
  //consistent hash
  unsigned long *chash;
  
  //ibv_mr of pm
  struct ibv_mr *pm_mr;
  //hash table of mempool
  std::unordered_map<unsigned short, struct mempool_meta *> *meta_map;
  std::deque<struct mempool_meta *> *free_meta;
};

typedef struct Addr{
  union{
    unsigned long val;
    struct {
      unsigned long offset : 48;
      unsigned long region_id : 16;
    };
  };
} Addr;

#endif